#include <kiddie/IRunnable.h>
#include <Object.h>
/*
 * Copyright (c) 2010, artur
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the author nor the names of any co-contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * kiddie-os
 * Created on: 14.04.2010
 *     Author: artur
 *
 */

#ifndef PCIENUMERATOR_H_
#define PCIENUMERATOR_H_

#include <kiddie/IRunnable.h>
#include <Object.h>

#define	PCI_NODEV	0xFFFF
/** PCI Configuration Space Address */
#define	PCI_CONF_ADR	0x0CF8
/** PCI Configuration Space Data */
#define	PCI_CONF_DATA	0x0CFC
/** PCI Mechanism Configuration */
#define	PCI_PMC			0x0CFB

/* PCI Configuration Address Space Layout (parts) */
#define PCI_COMMAND		0x04	/* 16 bits */
#define PCI_COMMAND_MASTER	0x4	/* Enable bus mastering */
#define PCI_INTERRUPT_LINE	0x3c	/* 8 bits */
#define PCI_INTERRUPT_PIN	0x3d	/* 8 bits */

#define PCI_DEV_MAX_FUNCS	8
#define PCI_CONF_HDR_MULTIFUNC	0x80

#define PCI_CONF_HDR_DEVREG		0x0
#define PCI_CONF_HDR_CMDREG		0x4
#define PCI_CONF_HDR_CLASSREG		0x8
#define PCI_CONF_HDR_TYPEREG		0xC

#define PCI_CONF_BAR_MAX	6
#define PCI_CONF_HDR_BAR0	0x10
#define PCI_CONF_HDR_BAR1 	0x14
#define PCI_CONF_HDR_BAR2 	0x18
#define PCI_CONF_HDR_BAR3 	0x1C
#define PCI_CONF_HDR_BAR4 	0x20
#define PCI_CONF_HDR_BAR5 	0x24
#define PCI_CONF_HDR_IRQ	0x3C

/** Simple PCI device description */
struct pci_dev
{
  /** Header */
  union
  {
    struct
    {
      unsigned short vendor_id;
      unsigned short dev_id;
    } struct_r0;
    u32 raw_r0;
  } r0;
  union
  {
    struct
    {
      unsigned short cmd;
      unsigned short status;
    } struct_r1;
    u32 raw_r1;
  } r1;
  union
  {
    struct
    {
      unsigned char rev_id;
      unsigned char prog_if;
      unsigned char subclass;
      unsigned char classcode;
    } struct_r2;
    u32 raw_r2;
  } r2;
  union
  {
    struct
    {
      unsigned char cachesiz;
      unsigned char latency;
      unsigned char type;
      unsigned char BIST;
    } struct_r3;
    u32 raw_r3;
  } r3;

  u32 bar[6];
  u32 cardbus;
  u32 subsys;
  u32 rombar;
  u32 capabilities;
  u32 reserved;

  union
  {
    struct
    {
      unsigned char irq;
      unsigned char pin;
      unsigned char min_grant;
      unsigned char max_latency;
    } irq_info;
    u32 irq_reg;
  } interrupts;

  /* bus device number */
  int bus_num;
  /* device number on that bus */
  int dev_num;
  int func_num;

  /* Memory in IO address space. Can be accsessed directly: inb, outb... */
  unsigned long io_mem;
  /* Mapped memory (not working right now) */
  unsigned long map_mem;

  /* Device 'body' */
  void *irq_handler;
  /* private device data */
  void *priv;
};

#define MAX_PCI_DEV	32

class PciEnumerator : public util::IRunnable, public Object
{
public:
  static util::Capabilities caps;
public:
  PciEnumerator();
  ~PciEnumerator();
  void
  entry(void *);
  void
  onEvent(kernel::irq::Event *);
  util::IRunnable &
  operator<<(kernel::cmd::CMD);

  static util::IRunnable *__init newInstance(util::Capabilities&);
  util::Capabilities
  getCaps(void);

private:
  void
  __scanPci(void);
  void
  __setMaster(struct pci_dev *pdev);
  vaddr_t iobase;
};

/* Vendor ID */
#define PCI_INTEL_ID   0x8086

/* Device IDs */
#define IXGBE_DEV_ID_82598               0x10B6
#define IXGBE_DEV_ID_82598_BX            0x1508
#define IXGBE_DEV_ID_82598AF_DUAL_PORT   0x10C6
#define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7
#define IXGBE_DEV_ID_82598AT             0x10C8
#define IXGBE_DEV_ID_82598AT2            0x150B
#define IXGBE_DEV_ID_82598EB_SFP_LOM     0x10DB
#define IXGBE_DEV_ID_82598EB_CX4         0x10DD
#define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC
#define IXGBE_DEV_ID_82598_DA_DUAL_PORT  0x10F1
#define IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM      0x10E1
#define IXGBE_DEV_ID_82598EB_XF_LR       0x10F4
#define IXGBE_DEV_ID_82599_KX4     0x10F7
#define IXGBE_DEV_ID_82599_KX4_MEZZ 0x1514
#define IXGBE_DEV_ID_82599_KR 0x1517
#define IXGBE_DEV_ID_82599_COMBO_BACKPLANE 0x10F8
#define IXGBE_DEV_ID_82599_CX4 0x10F9
#define IXGBE_DEV_ID_82599_SFP 0x10FB
#define IXGBE_DEV_ID_82599_SFP_EM 0x1507
#define IXGBE_DEV_ID_82599_XAUI_LOM 0x10FC

#endif /* PCIENUMERATOR_H_ */
